package com.grupit.module.user.web.gwt.client.pluggablefeatures.ui;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.CssResource.Import;
import com.google.gwt.resources.client.CssResource.ImportedWithPrefix;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;
import com.grupit.engine.util.Format;
import com.grupit.module.user.web.gwt.client.pluggablefeatures.ioc.NoteBoardView;
import com.grupit.module.user.web.gwt.client.pluggablefeatures.ui.NoteBoardViewImpl.NoteBoardViewAppearance.NoteBoardViewResources;
import com.grupit.module.user.web.gwt.client.ui.design.widget.MainBoardCenterPanel;
import com.grupit.module.user.web.gwt.client.ui.lookandfeel.Appearance;

import es.chaveweb.poZit.client.mvp.widget.PoZitBoardPanel;
import es.chaveweb.poZit.client.mvp.widget.PoZitData;
import es.chaveweb.poZit.client.ui.cell.PoZitCell.PoZitAppearance.PoZitCss;
import es.chaveweb.poZit.client.ui.widget.PoZitBoardPanelImpl;
import es.chaveweb.poZit.client.ui.widget.PoZitBoardPanelImpl.PoZitBoardPanelAppearance.PoZitBoardPanelCss;
import es.chaveweb.poZit.client.ui.widget.PoZitImpl;
import es.chaveweb.poZit.shared.proxy.PoZitProxy;

public class NoteBoardViewImpl extends Composite implements NoteBoardView {

	private static NoteBoardViewImplUiBinder uiBinder = GWT.create(NoteBoardViewImplUiBinder.class);

	interface NoteBoardViewImplUiBinder extends UiBinder<Widget, NoteBoardViewImpl> {
	}

	public static class NoteBoardViewAppearance extends Appearance<NoteBoardViewResources> {
		public NoteBoardViewAppearance(NoteBoardViewResources resources) {
			super(resources);
		}

		public static interface NoteBoardViewResources extends ClientBundle {
			@Import({ PoZitBoardPanelCss.class, PoZitCss.class })
			@Source({ NoteBoardViewCss.DEFAULT_CSS })
			NoteBoardViewCss noteBoardView();
		}

		@ImportedWithPrefix("noteBoardView")
		public interface NoteBoardViewCss extends CssResource {
			String DEFAULT_CSS = "NoteBoardViewImpl.css";

			String container();

			String newPozit();

			String minPoZitSize();
		}

		@Override
		public void ensureCssResourcesInjected() {
			this.resources.noteBoardView().ensureInjected();
		}
	}

	@UiField
	PoZitImpl newPozit;

	@UiField(provided = true)
	NoteBoardViewResources theme;

	@UiField
	HTMLPanel container;

	@UiField
	PoZitBoardPanelImpl myNotes;

	@UiField
	MainBoardCenterPanel boardPanels;

	private Presenter presenter;

	private String loggedUserTargetSystemId;

	public NoteBoardViewImpl() {
		NoteBoardViewAppearance appearance = new NoteBoardViewAppearance(
				GWT.<NoteBoardViewResources> create(NoteBoardViewResources.class));
		this.theme = appearance.getResources();
		initWidget(uiBinder.createAndBindUi(this));
	}

	@Override
	public void setPresenter(Presenter presenter) {
		this.presenter = presenter;
		this.myNotes.setPresenter(new PoZitBoardPanel.Presenter() {

			@Override
			public void changeNoteText(EntityProxyId<? extends PoZitProxy> noteId, String text) {
				NoteBoardViewImpl.this.presenter.changeNoteText(noteId, text);
			}

			@Override
			public void changeNoteCoord(EntityProxyId<? extends PoZitProxy> noteId, int x, int y) {
				NoteBoardViewImpl.this.presenter.changeNoteCoord(noteId, x, y);
			}

			@Override
			public void undoLastSendToBin() {
				NoteBoardViewImpl.this.presenter.undoSentToBin(NoteBoardViewImpl.this.loggedUserTargetSystemId);
			}

			@Override
			public void sendToBin(PoZitData toDelete, ConfirmResponse confirmResponse) {
				NoteBoardViewImpl.this.presenter.sendToBin(toDelete, NoteBoardViewImpl.this.loggedUserTargetSystemId,
						confirmResponse);
			}

			@Override
			public void createPoZit(int x, int y) {
				NoteBoardViewImpl.this.presenter.createPoZit(x, y, NoteBoardViewImpl.this.loggedUserTargetSystemId);
			}

			@Override
			public void clearBin() {
				NoteBoardViewImpl.this.presenter.clearBin(NoteBoardViewImpl.this.loggedUserTargetSystemId);
			}
		});
	}

	@UiHandler("newPozit")
	public void onNewPozitMouseDown(MouseDownEvent evt) {
		final Panel container = RootPanel.get();

		final PoZitImpl floatingNewPozit = new PoZitImpl();
		floatingNewPozit.setStyleName(this.theme.noteBoardView().minPoZitSize());

		final Style style = floatingNewPozit.getElement().getStyle();
		style.setPosition(Position.ABSOLUTE);
		style.setLeft(evt.getRelativeX(container.getElement()), Unit.PX);
		style.setTop(evt.getRelativeY(container.getElement()), Unit.PX);

		MouseMoveHandler mouseMoveHandler = new MouseMoveHandler() {

			@Override
			public void onMouseMove(MouseMoveEvent evt) {
				style.setLeft(evt.getRelativeX(container.getElement()), Unit.PX);
				style.setTop(evt.getRelativeY(container.getElement()), Unit.PX);
			}
		};

		floatingNewPozit.addMouseMoveHandler(mouseMoveHandler);

		floatingNewPozit.addMouseUpHandler(new MouseUpHandler() {

			@Override
			public void onMouseUp(MouseUpEvent event) {
				DOM.releaseCapture(floatingNewPozit.getElement());

				Widget myNotesBoardList = myNotes.boardListWidget().asWidget();
				Element myNotesHeading = myNotes.headingElement();
				int xBoardList = event.getRelativeX(myNotesBoardList.getElement());
				int yBoardList = event.getRelativeY(myNotesBoardList.getElement());
				int limitX = myNotesHeading.getOffsetWidth();
				int limitY = myNotesHeading.getOffsetHeight();

				if (xBoardList >= 0 && yBoardList >= 0
						&& xBoardList <= (myNotesBoardList.getOffsetWidth() - floatingNewPozit.getOffsetWidth())
						&& yBoardList <= (myNotesBoardList.getOffsetHeight() - floatingNewPozit.getOffsetHeight())) {
					assert (presenter != null) : Format.substitute(
							"El widget '{0}' necesita tener un presenter asociado. ¿Se te olvidó asignarlo?", this
									.getClass().getName());

					if (xBoardList < limitX && yBoardList < limitY) {
						int diffX = (limitX - xBoardList);
						int diffY = (limitY - yBoardList);
						if (diffX < diffY) {
							xBoardList = limitX;
						} else {
							yBoardList = limitY;
						}
					}

					presenter.createPoZit(xBoardList, yBoardList, null);
				}

				floatingNewPozit.removeFromParent();
			}
		});

		DOM.setCapture(floatingNewPozit.getElement());
		DOM.eventPreventDefault(DOM.eventGetCurrentEvent());

		container.add(floatingNewPozit);
	}

	@Override
	public PoZitBoardPanel noteBoardPanel(String forThisTargetSystemId) {
		// TODO Por ahora sólo devolvemos sí o sí el único que hay. Cambiar.
		if (forThisTargetSystemId.equals(this.loggedUserTargetSystemId)) {
			return this.myNotes;
		} else {
			return null;
		}
	}

	@Override
	public void setLoggedUserPanelTargetSystemId(String loggedUserTargetSystemId) {
		this.loggedUserTargetSystemId = loggedUserTargetSystemId;
	}
}
